package com.arpa.wms.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.arpa.ntocc.common.common.cache.PartyCache;
import com.arpa.ntocc.common.common.cache.ShipmentCache;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.CommonUtil;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.wms.cache.GoodsCache;
import com.arpa.wms.cache.UnitCache;
import com.arpa.wms.cache.WarehouseCache;
import com.arpa.wms.common.util.OrderIdGeneratorUtil;
import com.arpa.wms.domain.consts.NumConst;
import com.arpa.wms.domain.consts.TipConst;
import com.arpa.wms.domain.dto.AllocationDTO;
import com.arpa.wms.domain.dto.AllocationItemDTO;
import com.arpa.wms.domain.dto.GoodsUnitConversionDTO;
import com.arpa.wms.domain.entity.*;
import com.arpa.wms.domain.enums.AllocationStatusEnum;
import com.arpa.wms.domain.enums.DeliveryStatusEnum;
import com.arpa.wms.domain.enums.DeliveryTypeEnum;
import com.arpa.wms.domain.vo.AllocationItemVO;
import com.arpa.wms.domain.vo.AllocationVO;
import com.arpa.wms.domain.vo.GoodsUnitConversionVO;
import com.arpa.wms.mapper.AllocationMapper;
import com.arpa.wms.service.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * WMS调拨单 服务实现类
 * </p>
 *
 * @author LEO
 * @since 2020-11-17
 */
@Service
public class AllocationServiceImpl extends ServiceImpl<AllocationMapper, Allocation> implements IAllocationService {

    @Autowired
    private PartyCache partyCache;

    @Autowired
    private ShipmentCache shipmentCache;

    @Autowired
    private UnitCache unitCache;

    @Autowired
    private IAllocationItemService allocationItemService;

    @Autowired
    private IGoodsUnitConversionService goodsUnitConversionService;

    @Autowired
    private IDeliveryService deliveryService;

    @Autowired
    private IDeliveryItemService deliveryItemService;
    @Autowired
    private WarehouseCache warehouseCache;
    @Autowired
    private IReceiveItemService receiveItemService;
    @Autowired
    private GoodsCache goodsCache;

    /**
     * 保存
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor={Exception.class})
    public boolean save(Allocation entity) {

        //调出仓库与调入仓库不能一样
        if (entity.getSourceWarehouseCode().equals(entity.getTargetWarehouseCode())) {
            throw new ServiceException("调出仓库与调入仓库不能相同！！！");
        }
        entity.getAllocationItemList().stream().forEach(item -> {
            if(item.getAllocationUnitQuantity().compareTo(BigDecimal.ZERO) <= NumConst.NUM_ZERO) {
                throw new ServiceException(item.getGoodsName() + TipConst.ALLOCATION_NUM_NOT_LESS_ZERO);
            }
        });
        if(StrUtil.isBlank(entity.getCode())){
            entity.setCode(OrderIdGeneratorUtil.generatorOrderId(OrderIdGeneratorUtil.OrderTypeEnum.DB, entity.getShipmentCode(),UserUtil.getBranchCode()));
            entity.setShipmentName(shipmentCache.translate(entity.getShipmentCode()));
            entity.setSourceWarehouseName(warehouseCache.translate(entity.getSourceWarehouseCode()));
            entity.setTargetWarehouseName(warehouseCache.translate(entity.getTargetWarehouseCode()));
        }
        entity.setGroupCode(UserUtil.getBranchCode());
        if(StrUtil.isBlank(entity.getCreatedBy())){
            entity.setCreatedBy(UserUtil.getCode());
            entity.setCreatedName(partyCache.translate(UserUtil.getCode()));
        }
        entity.setModifiedBy(UserUtil.getCode());
        entity.setModifiedName(partyCache.translate(UserUtil.getCode()));

        entity.getAllocationItemList().forEach(item -> item.setAllocationQuantity(item.getAllocationUnitQuantity().multiply(item.getUnitConvertQuantity())));
        BigDecimal totalUnitQuantity = entity.getAllocationItemList().stream()
                // 将 Allocation对象的数量取出来map为Bigdecimal
                .map(AllocationItem::getAllocationUnitQuantity)
                // 使用reduce聚合函数,实现累加器
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        entity.setAllocationUnitQuantity(totalUnitQuantity);

        BigDecimal totalQuantity = entity.getAllocationItemList().stream()
                // 将 Allocation对象的数量取出来map为Bigdecimal
                .map(AllocationItem::getAllocationQuantity)
                // 使用reduce聚合函数,实现累加器
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        entity.setAllocationQuantity(totalQuantity);
        boolean flag = super.save(entity);
        if (flag) {
            this.saveItem(entity);
        }
        return flag;
    }

    /**
     * 保存 调拨单明细
     * @param entity
     */
    private void saveItem(Allocation entity) {
        entity.getAllocationItemList().forEach(r -> {
            r.setCode(IdUtil.simpleUUID());
            r.setAllocationCode(entity.getCode());
            r.setAllocationUnitName(unitCache.translate(r.getAllocationUnit()));
            r.setCreatedBy(entity.getCreatedBy());
            r.setCreatedName(partyCache.translate(UserUtil.getCode()));
            r.setGroupCode(UserUtil.getBranchCode());
        });
        //批量保存调拨单明细
        allocationItemService.saveBatch(entity.getAllocationItemList());
    }

    /**
     * 根据编码获取调拨单
     * @param code
     * @return
     */
    @Override
    public AllocationVO getOneByCode(String code) {
        Allocation allocation = getOne(new QueryWrapper<Allocation>().lambda().eq(Allocation::getCode, code).eq(Allocation::getGroupCode,UserUtil.getBranchCode()));
        if(ObjectUtil.isNull(allocation)) {
            throw new ServiceException(TipConst.ALLOCATION_NUMBER + code + TipConst.NOT_EXIST);
        }

        AllocationVO allocationVO = new AllocationVO();
        BeanUtils.copyProperties(allocation,allocationVO);

        AllocationItemDTO allocationItemDTO = new AllocationItemDTO();
        allocationItemDTO.setAllocationCode(code);
        allocationItemDTO.setPageSize(NumConst.NUM_NINETY_NINE_THOUSAND_NINE_HUNDRED_NINETY_NINE);
        //获取调拨单明细信息
        List<AllocationItemVO> allocationItemList = allocationItemService.queryList(allocationItemDTO);

        GoodsUnitConversionDTO goodsUnitConversionDTO = new GoodsUnitConversionDTO();
        goodsUnitConversionDTO.setPageSize(NumConst.NUM_NINETY_NINE_THOUSAND_NINE_HUNDRED_NINETY_NINE);
        List<GoodsUnitConversionVO> goodsUnitConversionList = goodsUnitConversionService.queryList(goodsUnitConversionDTO);

        allocationItemList.stream().forEach(item -> {
            List<GoodsUnitConversionVO> goodsUnitConversionVOList = Lists.newArrayList();
            goodsUnitConversionList.stream().forEach(goodsUnitConversionVO -> {
                if(goodsUnitConversionVO.getGoodsCode().equals(item.getGoodsCode())) {
                    goodsUnitConversionVOList.add(goodsUnitConversionVO);
                }
            });
            item.setGoodsUnitConversionList(goodsUnitConversionVOList);
        });

        allocationVO.setAllocationItemVO(allocationItemList);
        return allocationVO;
    }

    /**
     * 根据code更新实体
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor={Exception.class})
    public int updateByCode(Allocation entity) {
        entity.setShipmentName(shipmentCache.translate(entity.getShipmentCode()));
        if(StrUtil.isBlank(entity.getModifiedBy())){
            entity.setModifiedBy(UserUtil.getCode());
            entity.setModifiedName(partyCache.translate(UserUtil.getCode()));
        }

        //删除所有明细
        allocationItemService.remove(new QueryWrapper<AllocationItem>().lambda().eq(AllocationItem::getAllocationCode, entity.getCode()).eq(AllocationItem::getGroupCode,UserUtil.getBranchCode()));
        entity.getAllocationItemList().forEach(item -> item.setAllocationQuantity(item.getAllocationUnitQuantity().multiply(item.getUnitConvertQuantity())));
        BigDecimal unitQuantity = entity.getAllocationItemList().stream()
                // 将 Allocation对象的数量取出来map为Bigdecimal
                .map(AllocationItem::getAllocationUnitQuantity)
                // 使用reduce聚合函数,实现累加器
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        entity.setAllocationUnitQuantity(unitQuantity);
        BigDecimal quantity = entity.getAllocationItemList().stream().map(AllocationItem::getAllocationQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
        entity.setAllocationQuantity(quantity);
        //保存明细
        this.saveItem(entity);
        return baseMapper.update(entity,new QueryWrapper<Allocation>().lambda().eq(Allocation::getCode,entity.getCode()).eq(Allocation::getGroupCode,UserUtil.getBranchCode()));
    }

    /**
     * 查询列表
     * @param allocationDTO
     * @return
     */
    @Override
    public List<AllocationVO> queryList(AllocationDTO allocationDTO){
        allocationDTO.setGroupCode(UserUtil.getBranchCode());
        //排序字段名需要驼峰转数据库下划线类型字段名
        if(StringUtils.isNotEmpty(allocationDTO.getSortField())){
            allocationDTO.setSortField(CommonUtil.camel2Underline(allocationDTO.getSortField()));
        }
        List<AllocationVO> allocationVOList = baseMapper.queryList(allocationDTO);
        return allocationVOList;
    }

    /**
     * 查询合计,包含总数
     * @param allocationDTO
     * @return
     */
    @Override
    public AllocationVO queryListSum(AllocationDTO allocationDTO){
        allocationDTO.setGroupCode(UserUtil.getBranchCode());
        AllocationVO allocationVO = baseMapper.queryListSum(allocationDTO);
        return allocationVO;
    }



    /**
     * 更新 调拨单 状态
     * @param code
     * @param status
     * @return
     */
    @Override
    public int updateStatusByCode(String code, String status) {
        Allocation allocation = new Allocation();
        allocation.setCode(code);
        allocation.setStatus(status);
        allocation.setModifiedBy(UserUtil.getCode());
        allocation.setModifiedName(partyCache.translate(UserUtil.getCode()));

        return baseMapper.update(allocation, new QueryWrapper<Allocation>().lambda().eq(Allocation::getCode, allocation.getCode()).eq(Allocation::getGroupCode,UserUtil.getBranchCode()));
    }

    /***
     * 根据收货单回写Wms调拨单明细
     * @param receive
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void updateWmsAllocationInfo(Receive receive) {
        List<ReceiveItem> receiveItems = receiveItemService.list(new QueryWrapper<ReceiveItem>().lambda().eq(ReceiveItem::getReceiveCode, receive.getCode()).eq(ReceiveItem::getGroupCode,UserUtil.getBranchCode()));
        BigDecimal totalBasicQuantity = BigDecimal.ZERO;
        BigDecimal totalQuantity = BigDecimal.ZERO;
        for (ReceiveItem e: receiveItems) {
            Goods goods = goodsCache.getObj(e.getGoodsCode());
            // 计算出基本单位入库数量
            BigDecimal basicUnitQuantity = e.getInboundQuantity().multiply(e.getUnitConvertQuantity()).setScale(goods.getUnitPrecision().intValue(), BigDecimal.ROUND_HALF_UP);


            allocationItemService.update(new UpdateWrapper<AllocationItem>().lambda().eq(AllocationItem::getCode, e.getSourceItemCode())
                    .eq(AllocationItem::getGroupCode,UserUtil.getBranchCode())
                    .set(AllocationItem::getInboundQuantity, basicUnitQuantity)
                    .set(AllocationItem::getInboundUnitQuantity, e.getInboundQuantity())
            );

            totalBasicQuantity = totalBasicQuantity.add(basicUnitQuantity);
            totalQuantity = totalQuantity.add(e.getInboundQuantity());
        }

        // 更新采购单实际出库数量
        this.update(new UpdateWrapper<Allocation>().lambda()
                .eq(Allocation::getCode, receive.getSourceCode())
                .eq(Allocation::getGroupCode,UserUtil.getBranchCode())
                .set(Allocation::getInboundUnitQuantity, totalBasicQuantity)
                .set(Allocation::getInboundQuantity, totalQuantity));

    }


    /**
     * 审核数据列表
     *
     * @param dto
     * @return
     */
    @Override
    public List<AllocationVO> auditList(AllocationDTO dto) {
        //排序字段名需要驼峰转数据库下划线类型字段名
        if(StringUtils.isNotEmpty(dto.getSortField())){
            dto.setSortField(CommonUtil.camel2Underline(dto.getSortField()));
        }
        return baseMapper.auditList(dto);
    }

    @Override
    public AllocationVO auditListSum(AllocationDTO dto) {
        return baseMapper.auditListSum(dto);
    }
}
